package controller

import (
	"SelectCourse/dao"
	"SelectCourse/types"
	"errors"
	"fmt"
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"log"
	"net/http"
	"regexp"
	"strconv"
)

// Store : 全局 session 存储引擎
var Store = cookie.NewStore([]byte("secret"))

var cookieDomain string = "localhost"

func Login(c *gin.Context) {
	//获取登录用户对象 LoginRequest 对象
	var login types.LoginRequest
	var user types.TMember
	var response types.LoginResponse
	if err := c.ShouldBind(&login); err != nil {
		response.Code = types.ParamInvalid
		c.JSON(http.StatusOK, response)
		return
	}

	//验证登录是否成功？登陆成功 密码错误(密码错误 用户不存在 用户已删除)
	result := dao.Db.Where("username=?", login.Username).Find(&user)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) || user.Password != login.Password || user.IsDelete == 1 {
		response.Code = types.WrongPassword
		response.Data.UserID = string(strconv.Itoa(int(user.ID)))
		c.JSON(http.StatusOK, response)
		return
	}
	//登录成功，设置cookie, session, 并返回 LoginResponse 对象
	c.SetCookie("camp-session", string(types.LoginCookie), 3600, "/", cookieDomain, false, true)

	session := sessions.Default(c)
	session.Set("username", user.Username)
	session.Set("status", "logined")
	session.Save()
	log.Println(session.Get("username"))
	response.Code = types.OK
	response.Data.UserID = string(strconv.Itoa(int(user.ID)))
	c.JSON(http.StatusOK, response)
	return
}

func Logout(c *gin.Context) {
	var response types.LogoutResponse
	//检验当前用户是否登录
	session := sessions.Default(c)
	if status := session.Get("status"); status != "logined" {
		response.Code = types.LoginRequired
		c.JSON(http.StatusOK, response)
		return
	}
	fmt.Println(session.Get("username"))
	//登出当前用户，删除cookie, 清除session 返回 LogoutResponse 对象
	c.SetCookie("camp-session", string(types.LoginCookie), -1, "/", cookieDomain, false, true)
	session.Clear()
	session.Save()

	response.Code = types.OK
	c.JSON(http.StatusOK, response)
	return
}

func Whoami(c *gin.Context) {
	var user types.TMember
	var response types.WhoAmIResponse
	//检验当前用户是否登录
	session := sessions.Default(c)
	if status := session.Get("status"); status != "logined" {
		response.Code = types.LoginRequired
		c.JSON(http.StatusOK, response)
		return
	}
	//用户已登录则返回用户数据
	dao.Db.Where("username=?", session.Get("username")).Find(&user)
	response.Code = types.OK
	response.Data = user
	c.JSON(http.StatusOK, response)
	return
}

/**
 * @Autnor Roy
 * @TODO 添加成员的方法
 * @Date 19:55 2022/2/6
 **/
func AddMember(c *gin.Context) {
	var response types.CreateMemberResponse
	//鉴权，判断是已登录的否是管理员，不是就不给用
	session := sessions.Default(c)
	var loginedMember types.TMember
	log.Println(session.Get("username"))
	if session.Get("username") == nil {
		response.Code = types.LoginRequired
		c.JSON(http.StatusOK, response)
		return
	}
	loginedMember.Username = session.Get("username").(string)
	dao.Db.Where("username = ?", loginedMember.Username).First(&loginedMember)
	log.Println(loginedMember)
	if loginedMember.UserType != types.Admin {
		response.Code = types.PermDenied
		c.JSON(http.StatusOK, response)
		return
	}
	//绑定数据
	var member types.CreateMemberRequest
	if err := c.ShouldBind(&member); err != nil {
		log.Println(err)
		response.Code = types.ParamInvalid
		c.JSON(http.StatusOK, response)
		return
	}

	//usertype 判断
	if member.UserType != types.Admin && member.UserType != types.Student && member.UserType != types.Teacher {
		log.Println("userType只能为1||2||3")
		response.Code = types.ParamInvalid
		c.JSON(http.StatusOK, response)
		return
	}
	//各种长度判断
	if len(member.Nickname) > 20 || len(member.Nickname) < 4 || len(member.Username) > 20 || len(member.Username) < 8 || len(member.Password) > 20 || len(member.Password) < 8 {
		log.Println("长度不对,nickname [4-20]位，username[8-20]位，password[8-20]位")
		response.Code = types.ParamInvalid
		c.JSON(http.StatusOK, response)
		return
	}
	//利用网上抄的正则判断username是否合法
	var validUsername = regexp.MustCompile(`^[A-Za-z]+$`)
	if !validUsername.MatchString(member.Username) {
		log.Println("username格式不对，只支持大小写英文字母")
		response.Code = types.ParamInvalid
		c.JSON(http.StatusOK, response)
		return
	}
	//抄不到这样的正则，手写一个逻辑判断密码是否合法
	isContainsDigit := false
	isContainsBigLetter := false
	isContainsSmallLetter := false
	for i := 0; i < len(member.Password); i++ {
		if 47 < member.Password[i] && member.Password[i] < 58 {
			isContainsDigit = true
		}
		if 64 < member.Password[i] && member.Password[i] < 91 {
			isContainsBigLetter = true
		}
		if 96 < member.Password[i] && member.Password[i] < 123 {
			isContainsSmallLetter = true
		}
	}
	if !isContainsDigit || !isContainsBigLetter || !isContainsSmallLetter {
		log.Println("密码格式不对，需要同时包括大小写、数字")
		response.Code = types.ParamInvalid
		c.JSON(http.StatusOK, response)
		return
	}
	//用户名校验
	var member2 types.TMember
	member2.Username = member.Username
	dao.Db.Where("username = ?", member2.Username).First(&member2)
	log.Println(member2)
	if member2.Model.ID != 0 {
		log.Println("用户名重复！")
		response.Code = types.UserHasExisted
		c.JSON(http.StatusOK, response)
		return
	}
	//都合法，转换成数据库对象
	var member1 types.TMember
	member1.Nickname = member.Nickname
	member1.Username = member.Username
	member1.Password = member.Password
	member1.UserType = member.UserType
	//保存
	result := dao.Db.Create(&member1)
	if result.Error != nil {
		response.Code = types.UnknownError
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	//获取id以返回
	response.Data.UserID = string(strconv.Itoa(int(member1.ID)))
	response.Code = types.OK
	c.JSON(http.StatusOK, response)
	return
}
